classdef DroneModel < handle
    properties (Access = public)
        py_model
        is_trained = false
        feature_names = {'acc', 'vel', 'gyro', 'pos'}; % 默认与Python配置同步
        target_name = 'fa';
    end
    
    methods
        function obj = DroneModel(py_config)
            if nargin > 0
                % 尝试从Python配置同步参数
                try
                    obj.feature_names = cellfun(@char, cell(py_config.FEATURE_NAMES), 'UniformOutput', false);
                    obj.target_name = char(py_config.TARGET_NAME);
                catch
                    warning('无法从Python配置同步参数，使用默认值');
                end
                obj.py_model = py.drone_model.DroneAeroModel(py_config);
            end
        end
        
        function train(obj, trainData)
            try
                obj.validateTrainingData(trainData);
                py_data = obj.matlabToPythonData(trainData);
                obj.py_model.train(py.list(py_data));
                obj.is_trained = true;
                disp('训练成功完成');
            catch e
                error('训练出错: %s', e.message);
            end
        end
        
        function result = predict(obj, input_data, adapt_data)
            if ~obj.is_trained
                error('模型未训练');
            end
            
            try
                % 验证输入维度 (N×12矩阵，4个3维特征)
                if size(input_data, 2) ~= length(obj.feature_names)*3
                    error('输入数据应为N×%d矩阵（特征: %s）', ...
                        length(obj.feature_names)*3, strjoin(obj.feature_names, ', '));
                end
                
                py_input = py.numpy.array(input_data, 'float64');
                
                if nargin > 2 && ~isempty(adapt_data)
                    if size(adapt_data{1}, 2) ~= size(input_data, 2) || ...
                       size(adapt_data{2}, 2) ~= 3
                        error('适配数据维度不匹配');
                    end
                    py_adapt_X = py.numpy.array(adapt_data{1}, 'float64');
                    py_adapt_Y = py.numpy.array(adapt_data{2}, 'float64');
                    py_result = obj.py_model.predict(py_input, py.tuple({py_adapt_X, py_adapt_Y}));
                else
                    py_result = obj.py_model.predict(py_input);
                end
                
                result = struct();
                result.forces = double(py_result{'forces'});
                wind_cond = py_result{'wind_conditions'};
                if isa(wind_cond, 'py.str')
                    result.wind_conditions = char(wind_cond);
                else
                    result.wind_conditions = cellfun(@char, cell(wind_cond), 'UniformOutput', false);
                end
            catch e
                error('预测出错: %s', e.message);
            end
        end
        
        function saveModel(obj, path)
            if ~obj.is_trained
                error('模型未训练');
            end
            obj.py_model.save_model(path);
            disp(['模型已保存至: ', path]);
        end
        
        function loadModel(obj, path)
            obj.py_model.load_model(path);
            obj.is_trained = true;
            disp(['模型已加载: ', path]);
        end
    end
    
    methods (Access = private)
        function py_data = matlabToPythonData(obj, mat_data)
            py_data = cell(size(mat_data));
            for i = 1:length(mat_data)
                sample = mat_data{i};
                py_sample = py.dict();
                
                % 转换所有特征字段
                for j = 1:length(obj.feature_names)
                    field = obj.feature_names{j};
                    py_sample{field} = py.numpy.array(sample.(field), 'float64');
                end
                py_sample{obj.target_name} = py.numpy.array(sample.(obj.target_name), 'float64');
                py_sample{'condition'} = sample.condition;
                
                py_data{i} = py_sample;
            end
        end
        
        function validateTrainingData(obj, data)
            for i = 1:length(data)
                % 检查特征字段
                for j = 1:length(obj.feature_names)
                    field = obj.feature_names{j};
                    if ~isfield(data{i}, field) || size(data{i}.(field), 2) ~= 3
                        error('样本%d缺少%s字段或维度错误', i, field);
                    end
                end
                
                % 检查目标字段
                if ~isfield(data{i}, obj.target_name) || size(data{i}.(obj.target_name), 2) ~= 3
                    error('样本%d目标字段%s异常', i, obj.target_name);
                end
                
                % 检查features拼接是否正确（如果存在）
                if isfield(data{i}, 'features') && ...
                   size(data{i}.features, 2) ~= length(obj.feature_names)*3
                    error('样本%d特征拼接错误', i);
                end
            end
        end
    end
end
